package com.glq1218.authentication.service.impl;

import cn.hutool.http.Header;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.glq1218.authentication.dto.AuthenticationDTO;
import com.glq1218.authentication.dto.RegisterDTO;
import com.glq1218.authentication.model.AuthenticatedUser;
import com.glq1218.authentication.model.OnlineUser;
import com.glq1218.authentication.service.AuthenticationService;
import com.glq1218.authentication.vo.AuthenticationVO;
import com.glq1218.common.entity.User;
import com.glq1218.common.service.UserService;
import com.glq1218.common.util.JwtUtils;
import com.glq1218.common.util.RedisUtils;
import com.glq1218.common.util.ServletUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

/**
 * @author glq1218
 */
@Service
@RequiredArgsConstructor
public class AuthenticationServiceImpl implements AuthenticationService {
    private final RedisUtils redisUtils;

    private final AuthenticationManager authenticationManager;

    private final PasswordEncoder passwordEncoder;

    private final UserService userService;

    @Override
    public AuthenticationVO authenticate(AuthenticationDTO authenticationDTO) {
        Authentication authentication = authenticationManager.authenticate(
                UsernamePasswordAuthenticationToken.unauthenticated(
                        authenticationDTO.getUsername(),
                        authenticationDTO.getPassword()
                )
        );
        // 把认证信息存入SecurityContextHolder
        SecurityContextHolder.getContext().setAuthentication(authentication);
        AuthenticatedUser authenticatedUser = (AuthenticatedUser) authentication.getPrincipal();
        String jwt = JwtUtils.generateJwt(authenticatedUser.getUsername());
        // 把用户信息存入redis
        redisUtils.put(
                "loginUser:" + authenticationDTO.getUsername() + ":" + jwt,
                authenticatedUser,
                12L,
                TimeUnit.HOURS);
        // 获取登录设备信息
        HttpServletRequest request = ServletUtils.getRequest();
        UserAgent userAgent = UserAgentUtil.parse(request.getHeader(Header.USER_AGENT.toString()));
        String osName = userAgent.getOs().getName();
        String osVersion = userAgent.getOsVersion();
        String browser = userAgent.getBrowser().getName();
        boolean mobile = userAgent.getBrowser().isMobile();
        String ipAddress = ServletUtils.getIpAddress(request);
        OnlineUser onlineUser = OnlineUser.builder()
                .username(authenticatedUser.getUsername())
                .osName(osName)
                .osVersion(osVersion)
                .browser(browser)
                .ipAddress(ipAddress)
                .mobile(mobile)
                .build();
        // todo 后续在考虑是否需要将登录的用户信息存入redis
        /*redisUtils.put("onlineUser:" + jwt, onlineUser);*/
        return AuthenticationVO
                .builder()
                .token(jwt)
                .onlineUser(onlineUser)
                .build();
    }

    @Override
    public Object register(RegisterDTO registerDTO) {

        String username = registerDTO.getUsername();
        String password = registerDTO.getPassword();
        String confirmPassword = registerDTO.getConfirmPassword();
        if (!StringUtils.hasText(username)) {
            // throw new RuntimeException("用户名不能为空");
            return "用户名不能为空";
        }
        if (!StringUtils.hasText(password)) {
            throw new RuntimeException("密码不能为空");
        }
        if (!StringUtils.hasText(confirmPassword)) {
            throw new RuntimeException("确认密码不能为空");
        }
        if (!password.equals(confirmPassword)) {
            throw new RuntimeException("两次输入的密码不一致");
        }
        // 判断用户名是否已经存在
        if (userService.isExist(User::getUsername, username)) {
            throw new RuntimeException("用户名已存在");
        }
        User user = User.builder()
                .username(username)
                .password(passwordEncoder.encode(password))
                .build();
        if (!userService.save(user)) {
            throw new RuntimeException("注册失败，请联系管理员");
        }
        return "注册成功";
    }
}
